# Author: HZT
# Date: 2023/8/24

import json
import logging
import os
import random
import string
import time
from logging import handlers
from io import BytesIO
import win32clipboard
from PIL import Image
import yaml
from selenium.webdriver import ActionChains
import shutil
from config.config_loader import config
from selenium import webdriver
import pymysql
import pyautogui


# 获取驱动(默认作为收卡商浏览器驱动)
class UtilsDriver:
    # 获取WEB浏览器驱动
    _web_driver = None

    @classmethod
    def get_web_driver(cls):
        if cls._web_driver is None:
            cls._web_driver = webdriver.Chrome()
            cls._web_driver.maximize_window()
        return cls._web_driver

    # 关闭浏览器驱动
    @classmethod
    def quit_web_driver(cls):
        cls.get_web_driver().quit()
        cls._web_driver = None


# 获取驱动(默认作为出卡商浏览器驱动)
class UtilsDriver2:
    # 获取WEB浏览器驱动
    _web_driver = None

    @classmethod
    def get_web_driver(cls):
        if cls._web_driver is None:
            cls._web_driver = webdriver.Chrome()
            cls._web_driver.maximize_window()
        return cls._web_driver

    # 关闭浏览器驱动
    @classmethod
    def quit_web_driver(cls):
        cls.get_web_driver().quit()
        cls._web_driver = None


# 获取驱动(默认作为卡商管理浏览器驱动)
class UtilsDriver3:
    # 获取WEB浏览器驱动
    _web_driver = None

    @classmethod
    def get_web_driver(cls):
        if cls._web_driver is None:
            cls._web_driver = webdriver.Chrome()
            cls._web_driver.maximize_window()
        return cls._web_driver

    # 关闭浏览器驱动
    @classmethod
    def quit_web_driver(cls):
        cls.get_web_driver().quit()
        cls._web_driver = None


# 获取驱动(默认作为代付商浏览器驱动)
class UtilsDriver4:
    # 获取WEB浏览器驱动
    _web_driver = None

    @classmethod
    def get_web_driver(cls):
        if cls._web_driver is None:
            cls._web_driver = webdriver.Chrome()
            cls._web_driver.maximize_window()
        return cls._web_driver

    # 关闭浏览器驱动
    @classmethod
    def quit_web_driver(cls):
        cls.get_web_driver().quit()
        cls._web_driver = None


# 日志封装
class GetLog:
    _log = None

    @classmethod
    def get_log(cls):
        if cls._log is None:
            # 获取日志器
            cls._log = logging.getLogger()
            # 设置日志级别
            cls._log.setLevel(logging.INFO)
            # 获取处理器
            filename = config.DIR_PATH + "/log/card-{}.log".format(time.strftime("%Y-%m-%d %H-%M-%S"))
            # 创建日志文件
            open(filename, 'w', encoding='utf-8')
            # 输出到文件
            sf = logging.handlers.TimedRotatingFileHandler(filename=filename, when='H', interval=1, backupCount=5,
                                                           encoding='utf-8')
            # 输出到控制台
            sh = logging.StreamHandler()

            # 获取格式器
            fmt = '%(asctime)s %(levelname)s [%(name)s] [%(filename)s(%(funcName)s:%(lineno)d)] - %(message)s'
            formatter = logging.Formatter(fmt)
            # 将格式器添加到处理器
            sf.setFormatter(formatter)
            sh.setFormatter(formatter)
            # 将处理器添加到日志器
            cls._log.addHandler(sf)
            cls._log.addHandler(sh)
        # 返回日志器
        return cls._log


# 读取yaml
def read_yaml(filename):
    file_path = config.DIR_PATH + "/data/" + filename
    with open(file_path, "r", encoding="utf-8") as f:
        credentials = yaml.load(f, Loader=yaml.FullLoader)
    return credentials


# 读取配置文件中的session值并进行登录-卡商平台
def login_with_session(system, driver):
    session = config.SESSION[system]
    dict_cookie = {
        "name": "nexus_session",
        "value": session
    }
    driver.add_cookie(dict_cookie)
    driver.refresh()


# 读取配置文件中的session值并进行登录-代付平台
def login_with_session_df(system, driver):
    session = config.SESSION[system]
    dict_cookie = {
        "name": "playmentplatform_session",
        "value": session
    }
    driver.add_cookie(dict_cookie)
    driver.refresh()


def click_paste_img(filename, element, driver):
    # 在网页中粘贴图片,点击图片区域
    action = ActionChains(driver)
    update_img(filename)
    copy_img(filename)
    action.move_to_element(element).click().perform()
    # 模拟按下Ctrl键和V键
    pyautogui.hotkey('ctrl', 'v')
    time.sleep(2)


# 读取json
def read_json(filename):
    file_path = config.DIR_PATH + "/data/" + filename
    try:
        with open(file_path, 'r', encoding='utf-8') as file:
            data = json.load(file)
            output = []
            for item in data:
                output.append(tuple(item.values())[1:])
            return output
    except FileNotFoundError:
        print(filename + " json文件未找到")
    except Exception as e:
        print(f"An error occurred: {str(e)}")


# 卡商公司数据库——通过登录的用户名获取公司id
def get_cid_by_username(username):
    cid = DBUtil.select_one(
        f"""
        SELECT
            c.id
        FROM
            admin_users u,
            company_users cu,
            companies c
        WHERE
            u.id = cu.admin_user_id
        AND c.id = cu.company_id
        AND u.username = '{username}';
        """
    )
    return str(cid[0])


# 代付平台数据库——通过登录的用户名获取公司id
def get_cid_by_username_df(username):
    cid = DBUtilDF.select_one(
        f"""SELECT
                c.id 
           FROM
                admin_users u,
                payment_company_users cu,
                payment_companies c 
           WHERE
                u.id = cu.admin_user_id 
                AND c.id = cu.payment_company_id 
                AND u.username = '{username}';
        """
    )
    return str(cid[0])


# 卡商平台数据库——通过用户名获取公司余额
def get_db_ye(username):
    cid = get_cid_by_username(username)
    # 通过公司ID获取公司余额
    # 从数据库获取余额
    db_ye = DBUtil.select_one(
        f"""
        select
          (
            select
              balance_new
            from
              companies
            where
              id = {cid}
          ) + ifnull((
            select
              sum(rmb_amount)
            from
              transaction_records
            where
              status = 0
              and company_id = {cid}
          ), 0);
        """
    )
    return str(db_ye[0])


# 代付平台数据库——通过用户名获取公司余额
def get_db_ye_df(username):
    cid = get_cid_by_username_df(username)
    # 通过代付公司ID获取代付公司余额
    # 从数据库获取余额
    db_ye = DBUtilDF.select_one(
        f"""
        select
          (
            select
              balance_new
            from
              payment_companies
            where
              id = {cid}
          ) + ifnull((
            select
              sum(rmb_amount)
            from
              transaction_records
            where
              status = 0
              and company_id = {cid}
          ), 0);
        """
    )

    return str(db_ye[0])


# 卡商平台数据库——通过用户名获取公司授信余额
def get_db_sxye(username):
    cid = DBUtil.select_one(
        """
        SELECT
            c.id
        FROM
            admin_users u,
            company_users cu,
            companies c
        WHERE
            u.id = cu.admin_user_id
        AND c.id = cu.company_id
        AND u.username = '{}';
        """.format(username)
    )
    cid = str(cid[0])
    # 通过公司ID获取公司余额
    # 从数据库获取余额
    db_sxye = DBUtil.select_one(
        """
        select
         (
           select
             balance_new+credit
           from
             companies
           where
             id = {}
         ) + ifnull((
           select
             sum(rmb_amount)
           from
             transaction_records
           where
             status = 0
             and company_id = {}
         ), 0);
        """.format(
            cid, cid))

    return str(db_sxye[0])


# 封装数据库工具类
class DBUtil:
    db = config.DATABASE
    # 获取数据库主机地址
    host = db['host']
    # 获取数据库用户名
    username = db['username']
    # 获取数据库密码
    password = db['password']
    # 获取数据库名
    database = db['database']['ks']
    # 获取数据库端口号
    port = db['port']
    # 添加类属性
    conn = None

    @classmethod
    def __get_conn(cls):
        # 判断 conn 是否为空，如果是，再创建
        if cls.conn is None:
            cls.conn = pymysql.connect(host=cls.host, port=cls.port, user=cls.username,
                                       password=cls.password, database=cls.database, charset="utf8")
        # 返回 非空连接
        return cls.conn

    @classmethod
    def __close_conn(cls):
        # 判断，conn 不为空，需要关闭。
        if cls.conn is not None:
            cls.conn.close()
            cls.conn = None

    # 常用方法：查询一条
    @classmethod
    def select_one(cls, sql):
        cursor = None
        res = None
        try:
            # 获取连接
            cls.conn = cls.__get_conn()

            # 获取游标
            cursor = cls.conn.cursor()

            # 执行 查询语句
            cursor.execute(sql)

            # 提取一条结果
            res = cursor.fetchone()

        except Exception as err:
            print("查询sql错误：", str(err))
            GetLog.get_log().info("======>查询sql错误：{}".format(str(err)))
        finally:
            # 关闭游标
            cursor.close()

            # 关闭连接
            cls.__close_conn()

            # 将查询sql执行的 结果，返回
            return res

    # 常用方法：增删改
    @classmethod
    def uid_db(cls, sql):
        cursor = None
        try:
            # 获取连接
            cls.conn = cls.__get_conn()

            # 获取游标
            cursor = cls.conn.cursor()

            # 执行 uid 语句
            cursor.execute(sql)
            print("影响的行数：", cls.conn.affected_rows())

            # 提交事务
            cls.conn.commit()

        except Exception as err:
            # 回滚事务
            cls.conn.rollback()
            print("增删改 SQL 执行失败：", str(err))
            GetLog.get_log().info("======>增删改 SQL 执行失败：{}".format(str(err)))

        finally:
            # 关闭游标
            cursor.close()
            # 关闭连接
            cls.__close_conn()


# 代付数据库工具类
class DBUtilDF:
    db = config.DATABASE
    # 获取数据库主机地址
    host = db['host']
    # 获取数据库用户名
    username = db['username']
    # 获取数据库密码
    password = db['password']
    # 获取数据库名
    database = db['database']['df']
    # 获取数据库端口号
    port = db['port']
    # 添加类属性
    conn = None

    @classmethod
    def __get_conn(cls):
        # 判断 conn 是否为空，如果是，再创建
        if cls.conn is None:
            cls.conn = pymysql.connect(host=cls.host, port=cls.port, user=cls.username,
                                       password=cls.password, database=cls.database, charset="utf8")
        # 返回 非空连接
        return cls.conn

    @classmethod
    def __close_conn(cls):
        # 判断，conn 不为空，需要关闭。
        if cls.conn is not None:
            cls.conn.close()
            cls.conn = None

    # 常用方法：查询一条
    @classmethod
    def select_one(cls, sql):
        cursor = None
        res = None
        try:
            # 获取连接
            cls.conn = cls.__get_conn()

            # 获取游标
            cursor = cls.conn.cursor()

            # 执行 查询语句
            cursor.execute(sql)

            # 提取一条结果
            res = cursor.fetchone()

        except Exception as err:
            print("查询sql错误：", str(err))
            GetLog.get_log().info("======>查询sql错误：{}".format(str(err)))
        finally:
            # 关闭游标
            cursor.close()

            # 关闭连接
            cls.__close_conn()

            # 将查询sql执行的 结果，返回
            return res

    # 常用方法：增删改
    @classmethod
    def uid_db(cls, sql):
        cursor = None
        try:
            # 获取连接
            cls.conn = cls.__get_conn()

            # 获取游标
            cursor = cls.conn.cursor()

            # 执行 uid 语句
            cursor.execute(sql)
            print("影响的行数：", cls.conn.affected_rows())

            # 提交事务
            cls.conn.commit()

        except Exception as err:
            # 回滚事务
            cls.conn.rollback()
            print("增删改 SQL 执行失败：", str(err))
            GetLog.get_log().info("======>增删改 SQL 执行失败：{}".format(str(err)))

        finally:
            # 关闭游标
            cursor.close()
            # 关闭连接
            cls.__close_conn()


def copy_img(filename):
    filepath = config.DIR_PATH + "\\img\\card_bak\\" + filename
    image = Image.open(filepath)
    output = BytesIO()
    image.convert("RGB").save(output, "BMP")
    data = output.getvalue()[14:]
    output.close()
    win32clipboard.OpenClipboard()
    win32clipboard.EmptyClipboard()
    win32clipboard.SetClipboardData(win32clipboard.CF_DIB, data)
    win32clipboard.CloseClipboard()
    print("图片复制完成！")
    time.sleep(1)


def update_img(filename):
    # 源文件路径
    source_path = config.DIR_PATH + "\\img\\card\\" + filename
    # 目标文件夹路径
    target_folder = config.DIR_PATH + "\\img\\card_bak\\"
    # 确保目标文件夹存在
    if not os.path.exists(target_folder):
        os.makedirs(target_folder)

    # 复制图片文件到目标文件夹下
    from PIL import Image, ImageEnhance
    shutil.copy(source_path, target_folder)
    image_path = target_folder + filename
    # 打开图片
    image = Image.open(image_path)

    # 获取原始图片的尺寸
    width, height = image.size

    # 1.修改图片的尺寸
    new_width = width - random.randint(1, 50)

    # 使用thumbnail方法来修改图片的尺寸
    image.thumbnail((new_width, height))
    print("图片尺寸修改完成！")

    # 创建亮度增强对象
    enhancer = ImageEnhance.Brightness(image)

    # 2.调整亮度
    random_num = random.uniform(1.0, 1.5)
    adjusted_image = enhancer.enhance(random_num)
    print("图片亮度调整完成！")

    # 保存调整后的图片
    adjusted_image.save(image_path)

    # 关闭图片
    image.close()

    # # 修改图片属性
    # # 打开图片
    # image_path = target_folder+ filename
    # image = Image.open(image_path)
    #

    #
    # # 保存修改后的图片
    # # modified_image_path = image_path
    # image.save(image_path)
    #
    # # 关闭图片
    # image.close()
    #
    # print("图片尺寸修改完成！")


# 生成随机length长度的字符串（数字+大写字母）
def generate_random_string(length):
    # 定义包含数字和大写字母的字符集
    characters = string.digits + string.ascii_uppercase

    # 使用循环随机选择字符，生成字符串
    random_string = ''.join(random.choice(characters) for _ in range(length))

    return random_string


# 生成随机length长度的字符串（数字）
def generate_random_string_sz(length):
    # 生成随机数字字符
    digits = [str(random.randint(0, 9)) for _ in range(length)]
    # 将数字字符连接成字符串
    random_string = ''.join(digits)
    return random_string


def delete_log():
    # 删除img/log文件夹下所有文件
    img_log_path = os.path.join(os.getcwd(), "img", "log")
    for root, dirs, files in os.walk(img_log_path):
        for file in files:
            file_path = os.path.join(root, file)
            os.remove(file_path)

    # 删除log文件夹下所有文件
    log_path = os.path.join(os.getcwd(), "log")
    for root, dirs, files in os.walk(log_path):
        for file in files:
            file_path = os.path.join(root, file)
            os.remove(file_path)

    # 删除reports文件夹下所有.html结尾的文件
    reports_path = os.path.join(os.getcwd(), "reports")
    for root, dirs, files in os.walk(reports_path):
        for file in files:
            if file.endswith(".html"):
                file_path = os.path.join(root, file)
                os.remove(file_path)

    print("删除日志图片、日志、测试报告ojbk")


if __name__ == '__main__':
    # for i in range(1, 5):
    #     GetLog.get_log().warning("警告")
    # UtilsDriver.get_web_driver()
    # print(read_json("sk_hl.json"))
    # res = DBUtil.select_one("SELECT * FROM companies WHERE deleted_at IS NULL AND type = 2 and name='子拓出卡公司'")
    # print("查询结果为：", res)

    # DBUtil.uid_db("update t_book set is_delete = 1 where id = 1111;")

    # update_img("Vanilla2.png")
    # time.sleep(1)
    # copy_img("Vanilla2.png")
    # print(get_db_sxye("ztsk"))
    delete_log()
